/*
 * Copyright (c) 2021. Dylan Cai
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

@file:Suppress("unused")

package com.price.common.extend

import android.content.Context
import android.os.Build
import android.os.Looper

import java.io.File
import java.time.Instant

var onCrashHandlerListener: OnCrashHandlerListener? = null

//处理未捕获异常
inline fun handleUncaughtException(crossinline block: (Thread, Throwable) -> Unit) {
    val defaultCrashHandler = Thread.getDefaultUncaughtExceptionHandler()
    Thread.setDefaultUncaughtExceptionHandler { t, e ->
        block(t, e)

        if (onCrashHandlerListener?.onCrashHandler(t, e) == true) {
            return@setDefaultUncaughtExceptionHandler
        }

        defaultCrashHandler?.uncaughtException(t, e)
    }
}

inline fun handleMainThreadException(crossinline block: (Throwable) -> Unit) {
    mainThreadHandler.post {
        while (true) {
            try {
                Looper.loop()
            } catch (e: Throwable) {
                if (onCrashHandlerListener==null) {
                    block(e)
                } else
                    if (onCrashHandlerListener?.onCrashHandler(
                            Thread.currentThread(),
                            e
                        ) == false
                    ) {
                        doCustomCrashListener?.onCrash(e)
                    }
            }
        }
    }
}

fun Context.crashHandlerLister(handlerListener: OnCrashHandlerListener) {
    onCrashHandlerListener = handlerListener
}

//throwCrash 是否自行退出不按默认处理
fun Context.saveCrashLogLocally(dirPath: String = cacheDirPath) {
    handleUncaughtException { thread, e ->
        var now: Instant? = null
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            now = Instant.now()
        }
        File(dirPath).isExistOrCreateNewDir()
        val file = File(dirPath, "crash_${now?.format("yyyy-MM-dd")}.txt")
        if (file.isExistOrCreateNewFile()) {
            file.print(append = true) {
                println("Time:          ${now?.format("yyyy-MM-dd HH:mm:ss")}")
                println("App version:   $appVersionName ($appVersionCode)")
                println("OS version:    Android $sdkVersionName ($sdkVersionCode)")
                println("Manufacturer:  $deviceManufacturer")
                println("Model:         $deviceModel")
                println("Thread:        ${thread.name}")
                println()
                e.printStackTrace(this)
                println()
                println("-----------------------------------------------------")
                println()
            }
        }
    }
}

interface OnCrashHandlerListener {
    /**
     * 错误异常拦截
     *
     * @param thread 发生异常的线程
     * @param ex     异常类
     * @return true是拦截，false不拦击
     */
    fun onCrashHandler(thread: Thread, ex: Throwable): Boolean
}

